use std::collections::HashMap;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Mutex, OnceLock};
use std::thread;

use lazy_static::lazy_static;

use crate::gen_title;

pub fn ch4_17_1() {
    gen_title("ch4_17_1", 18);

    const MAX_ID: usize = usize::MAX / 2;

    println!("MAX_ID: {}", MAX_ID);
}

pub fn ch4_17_2() {
    gen_title("ch4_17_2", 18);

    static mut REQUEST_RECV: usize = 0;

    unsafe {
        REQUEST_RECV += 1;
        assert_eq!(REQUEST_RECV, 1);
        println!("REQUEST_RECV: {}", REQUEST_RECV);
    }
}

pub fn ch4_17_3() {
    gen_title("ch4_17_3", 18);

    static REQUEST_RECV: AtomicUsize = AtomicUsize::new(0);

    for _ in 0..100 {
        REQUEST_RECV.fetch_add(1, Ordering::Relaxed);
    }

    println!("REQUEST_RECV: {}", REQUEST_RECV.load(Ordering::Relaxed));
}

pub fn ch4_17_4() {
    gen_title("ch4_17_4", 18);

    struct Factory {
        factory_id: usize,
    }

    static GLOBAL_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);
    const MAX_ID: usize = usize::MAX / 2;

    fn generate_id() -> usize {
        let current_val = GLOBAL_ID_COUNTER.load(Ordering::Relaxed);
        if current_val > MAX_ID {
            panic!("Factory ids overflowed");
        }
        GLOBAL_ID_COUNTER.fetch_add(1, Ordering::Relaxed);
        let next_id = GLOBAL_ID_COUNTER.load(Ordering::Relaxed);
        if next_id > MAX_ID {
            panic!("Factory ids overflowed");
        }
        next_id
    }

    impl Factory {
        fn new() -> Self {
            Self {
                factory_id: generate_id(),
            }
        }
    }

    for _ in 0..100 {
        let factory = Factory::new();
        println!("factory_id: {}", factory.factory_id);
    }
}

pub fn ch4_17_5() {
    gen_title("ch4_17_5", 18);

    lazy_static! {
        static ref NAMES: Mutex<String> = Mutex::new(String::from("Sunface, Jack, Allen"));
    }

    let mut v = NAMES.lock().unwrap();
    v.push_str(", Myth");
    println!("{}", v);
}

pub fn ch4_17_6() {
    gen_title("ch4_17_6", 18);

    lazy_static! {
        static ref HASHMAP: HashMap<u32, &'static str> = {
            println!("初始化静态变量");
            let mut m = HashMap::new();
            m.insert(0, "foo");
            m.insert(1, "bar");
            m.insert(2, "baz");
            m
        };
    }

    println!("The entry for '0' is \"{}\".", HASHMAP.get(&0).unwrap());
    println!("The entry for '1' is \"{}\".", HASHMAP.get(&1).unwrap());
}

pub fn ch4_17_7() {
    gen_title("ch4_17_7", 18);

    #[derive(Debug)]
    struct Config {
        a: String,
        b: String,
    }

    static mut CONFIG: Option<&mut Config> = None;

    let c = Box::new(Config {
        a: "A".to_string(),
        b: "B".to_string(),
    });

    unsafe {
        CONFIG = Some(Box::leak(c));
        println!("CONFIG: {:?}", CONFIG);
    }
}

pub fn ch4_17_8() {
    gen_title("ch4_17_8", 18);

    #[derive(Debug)]
    struct Config {
        a: String,
        b: String,
    }

    static mut CONFIG: Option<&mut Config> = None;

    fn init() -> Option<&'static mut Config> {
        let c = Box::new(Config {
            a: "A".to_string(),
            b: "B".to_string(),
        });

        Some(Box::leak(c))
    }

    unsafe {
        CONFIG = init();
        println!("CONFIG: {:?}", CONFIG);
    }
}

pub fn ch4_17_9() {
    gen_title("ch4_17_9", 18);

    #[derive(Debug)]
    struct Logger;

    static LOGGER: OnceLock<Logger> = OnceLock::new();

    impl Logger {
        fn global() -> &'static Logger {
            LOGGER.get_or_init(|| {
                println!("Logger is being created...");
                Logger
            })
        }

        fn log(&self, message: String) {
            println!("{}", message);
        }
    }

    let handle = thread::spawn(|| {
        let logger = Logger::global();
        logger.log("thread message".to_string());
    });

    let logger = Logger::global();
    logger.log("some message".to_string());

    let logger2 = Logger::global();
    logger2.log("other message".to_string());

    handle.join().unwrap();
}
